Addressing Modes

How processors access operands to perform operations in computer architecture

📍🔍💻
⬇️
📍 🔍 📍 🔍 📍 🔍 📍 🔍 📍 🔍

Introduction to Addressing Modes

An addressing mode in computer architecture defines how a processor accesses operands to perform operations. It specifies the method or format by which the CPU identifies and retrieves data from memory or registers.

🧩

Fundamental Component

Addressing modes are essential in instruction set architecture (ISA)

🔄

Flexibility

Offer various ways to interact with data and instructions

Performance

Crucial for optimizing computing tasks and memory management

📋Types of Addressing Modes

  • 🔢 Immediate - Operand value within instruction
  • 📍 Direct - Memory address directly specified
  • 🔍 Indirect - Address points to operand location
  • 💾 Register - Operand in CPU register
  • 📊 Indexed - Offset added to base address
  • 🧭 Relative - Address relative to program counter
  • 🏗️ Base-Offset - Offset added to base register
  • 📚 Stack - Implicit access from stack top
  • ⬆️⬇️ Auto-increment/decrement - Address changes after access
  • 🗂️ Memory Indirect - Operand address in memory
🔢 🔢 🔢 🔢 🔢 🔢 🔢 🔢 🔢 🔢

Immediate Addressing Mode

In immediate addressing mode, the actual operand value is specified within the instruction itself rather than referencing a memory location.

💻Example

MOV A, #25
// This instruction moves the immediate value 25 directly into register A.

Advantages

🔧

Simplicity

Operands are directly specified, simplifying programming

🔒

Constants

Useful for literal values that don't change

Disadvantages

💾

Memory Usage

Wasteful if the same constant is used multiple times

🔄

Flexibility

Operands cannot be modified dynamically

🌍Real-World Example

In graphics programming, immediate addressing is often used to set constant values like color codes or transformation parameters. For example, when setting a clear color for a screen in OpenGL:

glClearColor(0.2f, 0.3f, 0.8f, 1.0f); // RGBA values as immediate operands
// These floating-point values are directly embedded in the instruction
📍 📍 📍 📍 📍 📍 📍 📍 📍 📍

Direct Addressing Mode

The operand's memory address is directly specified in the instruction.

💻Example

MOV A, 2000H
// This instruction moves the contents of memory location 2000H into register A.

Advantages

🔧

Simplicity

Simple and straightforward to implement

Efficiency

Efficient for accessing specific memory locations

Disadvantages

🔄

Flexibility

Limited flexibility as exact memory address must be known at compile-time

📦

Position-Dependent

Not suitable for position-independent code

🌍Real-World Example

In embedded systems, direct addressing is often used to access memory-mapped I/O devices. For example, reading the status of a hardware switch connected to a specific memory address:

#define SWITCH_STATUS 0x1000 // Memory address of switch status register

unsigned char read_switch_status() {
  return *((volatile unsigned char*)SWITCH_STATUS); // Direct memory access
}
🔍 🔍 🔍 🔍 🔍 🔍 🔍 🔍 🔍 🔍

Indirect Addressing Mode

The instruction specifies a memory address that holds the actual memory address of the operand.

💻Example

MOV A, @X
// If X contains 2000H, the contents of memory location 2000H are moved into register A.

Advantages

🔄

Flexibility

Allows for flexible memory referencing

🧩

Data Structures

Useful for accessing data structures with dynamic memory addresses

Disadvantages

⏱️

Speed

Requires extra memory access to fetch actual operand address

Performance

Slower compared to direct addressing due to additional memory access

🌍Real-World Example

Indirect addressing is commonly used with pointers in programming languages like C and C++. For example, when working with linked lists:

struct Node {
  int data;
  struct Node* next; // Pointer to next node
};

// Accessing data through a pointer (indirect addressing)
struct Node* current = head;
int value = current->data; // Indirect access to data
💾 💾 💾 💾 💾 💾 💾 💾 💾 💾

Register Addressing Mode

The operand is located in a processor register.

💻Example

MOV A, B
// This instruction moves the contents of register B into register A.

Advantages

Speed

Fastest access mode as it involves direct register-to-register transfer

🔄

Frequent Access

Suitable for frequently accessed data and arithmetic operations

Disadvantages

📊

Limited Number

Limited number of registers available

🔄

Context Switching

Register content might need to be saved and restored during context switches

🌍Real-World Example

Register addressing is extensively used in high-performance computing and graphics programming. For example, in x86 assembly language, function parameters are often passed in registers for faster execution:

; x86 assembly example - fast addition using registers
mov eax, 5 ; Move immediate value 5 into EAX register
mov ebx, 10 ; Move immediate value 10 into EBX register
add eax, ebx ; Add EBX to EAX, result stored in EAX
; Result (15) is now in EAX register
📊 📊 📊 📊 📊 📊 📊 📊 📊 📊

Indexed Addressing Mode

An offset is added to a base address to reach the operand.

💻Example

MOV A, [X + 2]
// This instruction moves the contents of memory location (X + 2) into register A.

Advantages

📋

Arrays

Useful for accessing elements in arrays and data structures

📦

Position-Independent

Supports position-independent code

Disadvantages

🧮

Arithmetic Overhead

Requires additional arithmetic operations to compute the effective address

🔄

Register Management

Overhead in maintaining and updating the base register

🌍Real-World Example

Indexed addressing is fundamental for array operations in programming. In C, when accessing array elements, the compiler typically generates code using indexed addressing:

int array[10];
int sum = 0;

// Compiler generates indexed addressing for array access
for (int i = 0; i < 10; i++) {
  sum += array[i]; // Accesses array[base + i*sizeof(int)]
}
🧭 🧭 🧭 🧭 🧭 🧭 🧭 🧭 🧭 🧭

Relative Addressing Mode

The operand's address is calculated relative to the program counter or instruction pointer.

💻Example

JMP LABEL
// This instruction jumps to the address specified by LABEL,
// which is a relative address from the current instruction.

Advantages

📦

Position-Independent

Supports position-independent code

🔄

Code Relocation

Simplifies code relocation and memory management

Disadvantages

📏

Limited Range

Limited range of relative addressing depending on instruction format

⚠️

Calculation Errors

Risk of errors if the offset is not correctly calculated

🌍Real-World Example

Relative addressing is crucial for creating position-independent code, which is essential for shared libraries and dynamic linking. In x86 assembly, branch instructions often use relative addressing:

; x86 assembly example - conditional jump using relative addressing
cmp eax, ebx ; Compare EAX and EBX
jne not_equal ; Jump if not equal (relative to current position)

; Equal case
mov ecx, 1
jmp end_compare

not_equal:
mov ecx, 0

end_compare:
; ECX now contains 1 if EAX == EBX, 0 otherwise
🏗️ 🏗️ 🏗️ 🏗️ 🏗️ 🏗️ 🏗️ 🏗️ 🏗️ 🏗️

Base or Base-Offset Addressing Mode

An offset added to a base address stored in a register or specified in the instruction.

💻Example

MOV A, [BASE + OFFSET]
// This instruction moves the contents of memory location
// (BASE + OFFSET) into register A.

Advantages

📋

Data Structures

Supports efficient access to data structures and arrays

🧩

Modular Programming

Facilitates modular programming and data segmentation

Disadvantages

💾

Additional Storage

Requires additional registers or memory locations to store base addresses

🧩

Complexity

Complexity in managing multiple base registers in larger programs

🌍Real-World Example

Base-offset addressing is commonly used in accessing fields within structures or objects. In C++, when accessing a member of a class or struct:

struct Person {
  char name[50];
  int age;
  float height;
};

void print_age(Person* person_ptr) {
  // Base-offset addressing: base = person_ptr, offset = offsetof(Person, age)
  std::cout << "Age: " << person_ptr->age << std::endl;
}
📚 📚 📚 📚 📚 📚 📚 📚 📚 📚

Stack Addressing Mode

Operands are implicitly accessed from the top of the stack.

💻Example

PUSH A
// This instruction pushes the contents of register A onto the stack.

Advantages

📚

LIFO Structure

Supports last-in-first-out (LIFO) data structures

📞

Function Calls

Facilitates function calls and parameter passing

Disadvantages

⏱️

Slower Access

Slower access compared to register or direct addressing modes

⚠️

Stack Limitations

Limited stack size and potential for stack overflow

🌍Real-World Example

Stack addressing is fundamental for function calls in most programming languages. In x86 architecture, the CALL instruction uses stack addressing to save the return address:

; x86 assembly example - function call using stack
call my_function ; Pushes return address onto stack and jumps to my_function

my_function:
  push ebp ; Save old base pointer
  mov ebp, esp ; Set new base pointer
  sub esp, 8 ; Allocate 8 bytes for local variables

  ; Function body here

  mov esp, ebp ; Deallocate local variables
  pop ebp ; Restore old base pointer
  ret ; Pop return address and jump back
⬆️ ⬇️ ⬆️ ⬇️ ⬆️ ⬇️ ⬆️ ⬇️ ⬆️ ⬇️

Auto-increment and Auto-decrement Addressing Mode

The memory address automatically increments or decrements after each access.

💻Example

LDA [X+]
// This instruction loads the contents of memory at address X
// into the accumulator and increments X.

Advantages

🔄

Sequential Access

Simplifies sequential memory access operations

🔁

Loop Optimization

Reduces the need for explicit address manipulation in loops

Disadvantages

🏗️

Limited Support

Limited support in modern architectures

⚠️

Side Effects

Requires careful management to avoid unintended side effects

🌍Real-World Example

Auto-increment and auto-decrement addressing modes are particularly useful in array processing and string operations. In ARM assembly, these modes are commonly used:

; ARM assembly example - string copy using auto-increment
; R0 = source address, R1 = destination address, R2 = length
copy_loop:
  LDRB R3, [R0], #1 ; Load byte from source, auto-increment R0
  STRB R3, [R1], #1 ; Store byte to destination, auto-increment R1
  SUBS R2, R2, #1 ; Decrement counter
  BNE copy_loop ; Branch if not zero
🗂️ 🗂️ 🗂️ 🗂️ 🗂️ 🗂️ 🗂️ 🗂️ 🗂️ 🗂️

Memory Indirect Addressing Mode

Similar to indirect addressing, but the operand address is located in memory.

💻Example

MOV A, @2000H
// This instruction moves the contents of the memory address
// stored at 2000H into register A.

Advantages

🔄

Dynamic Memory

Flexibility in accessing dynamically allocated memory

🧩

Complex Structures

Supports complex data structures and pointers

Disadvantages

⏱️

Access Time

Increased memory access time due to additional indirection

⚠️

Pointer Errors

Potential for pointer errors and memory leaks

🌍Real-World Example

Memory indirect addressing is used in systems with virtual memory and paging. In operating systems, page tables often use multiple levels of indirection:

// Simplified example of multi-level page table lookup
// In x86-64 with 4-level paging:

struct PageTableEntry {
  uint64_t present : 1;
  uint64_t writable : 1;
  uint64_t user_accessible : 1;
  uint64_t page_frame_number : 40;
  // ... other flags
};

// Virtual address translation (simplified)
uint64_t translate_address(uint64_t virtual_address, PageTableEntry* pml4_table) {
  // Extract indices from virtual address
  uint16_t pml4_index = (virtual_address >> 39) & 0x1FF;
  uint16_t pdpt_index = (virtual_address >> 30) & 0x1FF;
  uint16_t pd_index = (virtual_address >> 21) & 0x1FF;
  uint16_t pt_index = (virtual_address >> 12) & 0x1FF;

  // Memory indirect addressing through multiple levels
  PageTableEntry* pdpt = (PageTableEntry*)(pml4_table[pml4_index].page_frame_number << 12);
  PageTableEntry* pd = (PageTableEntry*)(pdpt[pdpt_index].page_frame_number << 12);
  PageTableEntry* pt = (PageTableEntry*)(pd[pd_index].page_frame_number << 12);

  return (pt[pt_index].page_frame_number << 12) | (virtual_address & 0xFFF);
}